import * as fs from 'fs';
import { getTpl, postTpl, serviceHead } from '../templates';
import { nunjucks } from '../templates/nunjucks';
import {
  arrayToCamelCase,
  formatModelName,
  generateSvcName,
  generateSvcParamsTypeName,
  log,
} from '../utils';

export class ServicesGenerator {
  private path: string;
  constructor(jsonPath: string) {
    this.path = jsonPath;
  }

  public start() {
    this.writeSvc();
  }

  // 读取文件
  public readJson() {
    const content = fs.readFileSync(this.path, 'utf-8');

    return JSON.parse(content);
  }

  // 读取paths字段
  public getPaths() {
    const json = this.readJson();
    return json.paths;
  }

  public getTags() {
    const json = this.readJson();
    return json.tags;
  }

  // 根据tag名称，查找对应的接口
  private findPathByTagName(tagName: string) {
    const paths = this.getPaths();
    const keys = Object.keys(paths);

    const result = keys.reduce((acc, cur) => {
      const path = paths[cur];
      const tags = path.get?.tags || path.post?.tags;
      if (tags.includes(tagName)) {
        return { ...acc, [cur]: path };
      }
      return acc;
    }, {});

    return result;
  }

  private writeSvc() {
    const tags = this.getTags();

    tags.forEach((cur) => {
      const { name } = cur;
      const paths = this.findPathByTagName(name);
      const { content, shouldImportFromQs } = this.generateService(paths);
      const fileHead = nunjucks.renderString(serviceHead, {
        shouldImportFromQs,
      });
      fs.writeFileSync(`./api/${name}.ts`, fileHead + content, 'utf-8');
      log(`生成${name}.ts成功`);
    }, '');

    this.writeExportIndex(tags);
  }

  private generateService(paths) {
    const keys = Object.keys(paths);
    let shouldImportFromQs = false;
    const content = keys.reduce((acc, cur) => {
      const path = paths[cur];
      const method = path.get || path.post;
      const { summary, parameters, responses } = method;
      const ignore = method['x-ignoreParameters'] || [];
      const params = (parameters || []).filter((item) => {
        const { name } = item;
        if (ignore.length === 0) {
          return true;
        }
        return !ignore.find((v) => v[name]);
      });

      const name = generateSvcName(cur, path.get ? 'get' : 'post');
      let paramsType = generateSvcParamsTypeName(
        cur,
        path.get ? 'Get' : 'Post'
      );
      const url = cur;
      const schema = responses?.['200']?.schema;
      let respModel = 'unknown';

      if (schema?.originalRef) {
        respModel = formatModelName(schema.originalRef);
      } else if (schema?.type === 'array') {
        respModel = formatModelName(schema.items.originalRef) + '[]';
      }

      const findParam = params.find((item) => item.name === 'param');

      if (findParam) {
        paramsType = paramsType + '["param"]';
      }

      const str = nunjucks.renderString(path.get ? getTpl : postTpl, {
        summary,
        name,
        paramsType: params.length > 0 ? paramsType : undefined,
        url,
        respModel: respModel === 'unknown' ? respModel : 'API.' + respModel,
      });

      if (params.length > 0 && path.get) {
        shouldImportFromQs = true;
      }

      return acc + str;
    }, '');

    return {
      content,
      shouldImportFromQs,
    };
  }

  writeExportIndex(tags) {
    const content = tags.reduce((acc, cur) => {
      return acc + `export * from './${cur.name}'\n`;
    }, '');

    fs.writeFileSync('./api/index.ts', content, 'utf-8');
    log('service总入口生成成功');
    log('程序执行完毕');
  }
}
